home *** CD-ROM | disk | FTP | other *** search
- How To Disassemble A Windows Program
-
- I think this small exercise (shamelessly abducted from Schulman's book
- -> see here) could be very helpful for all the future crackers trying
- to get some bearings during their difficult disassembly of Windows
- programs.
-
- One of the problems in reverse engineering, is that nobody teaches you
- how to do it, and you have mostly to learn alone the relevant
- techniques, loosing an enormous amount of time.
-
- Disassembling Windows with a reverse engineering approach is *very*
- useful for actual cracking purposes, and it's time to form a new
- generation of Windows crackers, since the ghastly Microsoft domination
- will not easily be crushed without many more good crackers to help us.
- What +ORC writes and teaches in his lessons is fundamental, but
- unfortunately he does not teach the "elementary" side of cracking
- Windows (for DOS cracking, on the contrary, the Crackbook of Uncle Joe
- is a good primer for beginners and intermediate alike), so I'll try to
- help here to form a strong generation of little strong crackers... as
- +ORC wrote to me: "we are all throwing seeds in the air, some of them
- will land astray, but some of them will grow".
-
- Remember that cracking Windows is *very* different, in approach and in
- techniques, from cracking DOS. The older ones (that I unconditionally
- respect) do not seem to grab it totally... they are probably so
- experienced that they can use more or less the same techniques in
- cracking all OSs... but in my (humble) opinion, that's not necessarily
- the best approach... you see, cracking Windows is "puzzle solving",
- cracking DOS is "playing chess"... you'll understand what I mean if
- you read what follows.
-
- Please do excuse my shortcomings both in the techniques I teach (I am
- an autodidact) and in the language I use.
-
- If at any time you feel you should need more references, check the
- Windows 3.1. SDK Programmer's Reference, Volume 1: Overview, Chapter
- 22, Windows Application Startup.
-
- A little knowledge of the C language is required in order to
- understand a part of the following (you better understand it right
- now: the only existing programming language is C, most applications
- are written in C, "real" programmers use C... you may dislike it, but
- that's the reality, so you better get a little knowledge of C
- programming as soon as you can, if you want to crack more
- effectively... you'll find enough C tutorials on the net). This said,
- most of the following can be used even if you do not know C.
-
- Disassembling Taskman
-
- As example for this introduction, I have chosen Taskman.exe, the small
- program you'll find inside your C:\WINDOWS directory... you can invoke
- it anytime typing CTRL+ESC in Windows 3.1.
-
- I have done it because Schulman has already (very well) worked on it,
- and therefore he spares me a lot of work, and also because I agree
- totally with him in his choice: Taskman it's a very good example for
- all newbys to Windows cracking. Actually it's a pity that you cannot
- (yet) find Schulman's books on the net... I believe they should be
- indisputably there! (Anybody with a good scanner reading this?).
-
- Let's start from the beginning... by looking at TASKMAN's startup
- code. Taskman is a very small win 3.1 program, but it's rich in
- surprises, as you'll see. After you disassembly taskman.exe with WCB
- (see below) and *after* you have printed the listing, you may use the
- "Loader" utility to pop out inside winice at the beginning of Taskman:
-
- start:
- 1FBF:4B9 33ED XOR BP,BP ;begins
- 1FBF:4BB 55 PUSH BP ;save BP
- 1FBF:4BC 9A8D262701 CALL KERNEL!INITTASK
- ...
-
- So we are set for snooping around "live", but first (and that's very
- important for Windows programs) we have to prepare a good disassembled
- listing of our target. You see, in DOS such a work does not make much
- sense, because the disassembled listing would not differ much from
- what you get on screen through softice, but in Windows, on the
- contrary, we can get quite a lot more out of all the information that
- is already present inside our target. The following explains this
- point:
-
- You can use any good disassembler (like Winsourcer, from V
- communication, a good version, cracked by the ubiquitous Marquis de
- Soiree, is available on the web) but i'll use the disassembled listing
- of WCB (Windows CodeBack -> download version 1.5. from my "tools"
- page: here).
-
- WCB is a very good Win 3.1. disassembler, created by the ungarian
- codemaster Leslie Pusztai (pusztail@tigris.klte.hu), and, in my modest
- opinion, it's far better than sourcer. If you use it, remember that it
- works from DOS: the main rule is to create first of all the *.EXL
- files for the necessary "mysterious" *.dll with the command:
-
- wcb -x [mysterious.dll]and you'll be able, afterwards, to disassemble
- the *.exe that called them.
-
- But all this is not necessary for humble Taskman.exe, where we get
- following header information: Filename: TASKMAN.EXE Type: Segmented
- executable Module description: Windows Task Manager 3.1 Module name:
- TASKMAN Imported modules:
-
- Filename: TASKMAN.EXE
- Type: Segmented executable
- Module description: Windows Task Manager 3.1
- Module name: TASKMAN
-
- Imported modules:
- 1: KERNEL
- 2: USER
-
- Exported names by location:
- 1:007B 1 TASKMANDLGPROC
-
- Program entry point: 1:04B9
- WinMain: 1:03AE
-
- and we can get straight the entry point code:
- 1.04B9 ; Program_entry_point
- 1.04B9 >33ED xor bp, bp
- 1.04BB 55 push bp
- 1.04BC 9AFFFF0000 call KERNEL.INITTASK
- 1.04C1 0BC0 or ax, ax
- 1.04C3 744E je 0513
- 1.04C5 81C10001 add cx, 0100
- 1.04C9 7248 jb 0513
- 1.04CB 890E3000 mov [0030], cx
- 1.04CF 89363200 mov [0032], si
- 1.04D3 893E3400 mov [0034], di
- 1.04D7 891E3600 mov [0036], bx
- 1.04DB 8C063800 mov [0038], es
- 1.04DF 89163A00 mov [003A], dx
- 1.04E3 33C0 xor ax, ax
- 1.04E5 50 push ax
- 1.04E6 9AFFFF0000 call KERNEL.WAITEVENT
- 1.04EB FF363400 push word ptr [0034]
- 1.04EF 9AFFFF0000 call USER.INITAPP
- 1.04F4 0BC0 or ax, ax
- 1.04F6 741B je 0513
- 1.04F8 FF363400 push word ptr [0034]
- 1.04FC FF363200 push word ptr [0032]
- 1.0500 FF363800 push word ptr [0038]
- 1.0504 FF363600 push word ptr [0036]
- 1.0508 FF363A00 push word ptr [003A]
- 1.050C E89FFE call WinMain
- 1.050F 50 push ax
- 1.0510 E890FF call 04A3
-
- This is similar to the standard startup code that you'll find in
- nearly *every* Windows program. It calls three functions: InitTask(),
- WaitEvent(), and InitApp().
-
- We know jolly well about InitTask(), but let's imagine that we would
- have here a more mysterious routine than these, and that we would like
- to know what for items are hold in the CX, SI etc. register on return
- from InitTask() without disassembling everything everywhere... how
- should we proceed?
-
- First of all let's see if the locations [0030] - [003A] are used
- elsewhere in our program... this is typical when you work with
- disassembled listings: to find out what one block of code means, you
- need most of the time to look first at some other block of code. Let's
- see.. well, yes! Most of the locations are used again a few lines down
- (1.04F8 to 1.0508).
-
- Five words are being pushed on the stack as parameters to WinMain().
- If only we knew what those enigmatic parameter were... but wait: we do
- actually know what those parameters are! WinMain(), the function being
- called from this code, always looks like:
-
- int PASCAL WinMain(WORD hInstance, WORD hPrevInstance,
- LPSTR lpCmdLine, int nCmdShow);
-
- And we (should) know that in the Pascal calling convention, which is
- used extensively in Windows because it produces smaller code than the
- cdecl calling convention, arguments are pushed on the stack in the
- same order as they appear inside the function declaration. That's a
- good news for all little crackers!
-
- Thus, in our example, [0034] must be hInstance, [0032] must be
- hPrevinstance, [0038]:[0036] are segment and offset of lpcmdline and
- [003A] must be nCmdshow.
-
- What makes this important is that we can now go and replace *every*
- occurrence of [0034] by a more useful name such as hInstance, every
- occurrence of [0032] by hPrevInstance and so on. This clarify not just
- this section of the listing, but every section of the listing that
- refers to these variables. Such global substitutions of useful names
- for placeholder names or addresses is indispensable when working with
- a disassembled listing. After applying these changes to the fragment
- shown earlier, we end up with something more understandable:
-
- 1.04CB 890E3000 mov [0030], cx
- 1.04CF 89363200 mov hPrevInstance, si
- 1.04D3 893E3400 mov hInstance, di
- 1.04D7 891E3600 mov lpCmdLine+2, bx
- 1.04DB 8C063800 mov lpCmdLine, es
- 1.04DF 89163A00 mov nCmdShow, dx
- 1.04E3 33C0 xor ax, ax
-
- 1.04E5 50 push ax
- 1.04E6 9AFFFF0000 call KERNEL.WAITEVENT
- 1.04EB FF363400 push word ptr hInstance
- 1.04EF 9AFFFF0000 call USER.INITAPP
- 1.04F4 0BC0 or ax, ax
- 1.04F6 741B je 0513
- 1.04F8 FF363400 push word ptr hInstance
- 1.04FC FF363200 push word ptr hPrevInstance
- 1.0500 FF363800 push word ptr lpCmdLine
- 1.0504 FF363600 push word ptr lpCmdLine+2
- 1.0508 FF363A00 push word ptr nCmdShow
- 1.050C E89FFE call WinMain
-
- Thus if we didn't already know what InitTask() returns in various
- register (our Taskman here is only an example for your later work on
- much more mysterious target programs), we could find it out right now,
- by working backwards from the parameters to WinMain(). Windows
- disassembling (and cracking) is like puzzle solving: the more little
- pieces fall into place, the more you get the global picture. Trying to
- disassemble Windows programs without this aid would be unhealthy: you
- would soon delve inside *hundreds* of irrelevant calls, only because
- you did not do your disassemble homework in the first place.
-
- It was useful to look at the startup code because it illustrated the
- general principle of trying to substitute useful names such as
- hPrevInstance for useless labels such as [0034]. But, generally, the
- first place we'll look examining a Windows program is WinMain(). Here
- the code from WCB:
-
- 1.03AE ; WinMain
- 1.03AE >55 push bp
- 1.03AF 8BEC mov bp, sp
- 1.03B1 83EC12 sub sp, 0012
- 1.03B4 57 push di
- 1.03B5 56 push si
- 1.03B6 2BFF sub di, di
- 1.03B8 397E0A cmp [bp+0A], di
- 1.03BB 7405 je 03C2
- 1.03BD 2BC0 sub ax, ax
- 1.03BF E9CC00 jmp 048E
-
- 1.03C2 >C47606 les si, [bp+06]
- 1.03C5 26803C00 cmp byte ptr es:[si], 00
- 1.03C9 7453 je 041E
- 1.03CB 897EF2 mov [bp-0E], di
- 1.03CE EB1E jmp 03EE
-
- 1.03D0 >26803C20 cmp byte ptr es:[si], 20
- 1.03D4 741E je 03F4
- 1.03D6 B80A00 mov ax, 000A
- 1.03D9 F72E1000 imul word ptr [0010]
- 1.03DD A31000 mov [0010], ax
- 1.03E0 8BDE mov bx, si
- 1.03E2 46 inc si
- 1.03E3 268A07 mov al, byte ptr es:[bx]
- 1.03E6 98 cbw
- 1.03E7 2D3000 sub ax, 0030
- 1.03EA 01061000 add [0010], ax
-
- 1.03EE >26803C00 cmp byte ptr es:[si], 00
- 1.03F2 75DC jne 03D0
-
- 1.03F4 >26803C00 cmp byte ptr es:[si], 00
- 1.03F8 741B je 0415
- 1.03FA 46 inc si
- 1.03FB EB18 jmp 0415
-
- 1.03FD >B80A00 mov ax, 000A
- 1.0400 F72E1200 imul word ptr [0012]
- 1.0404 A31200 mov [0012], ax
- 1.0407 8BDE mov bx, si
- 1.0409 46 inc si
- 1.040A 268A07 mov al, byte ptr es:[bx]
- 1.040D 98 cbw
- 1.040E 2D3000 sub ax, 0030
- 1.0411 01061200 add [0012], ax
-
- 1.0415 >26803C00 cmp byte ptr es:[si], 00
- 1.0419 75E2 jne 03FD
- 1.041B 8B7EF2 mov di, [bp-0E]
-
- 1.041E >6A29 push 0029
-
- 1.0420 9AF9000000 call USER.GETSYSTEMMETRICS
- 1.0425 50 push ax
- 1.0426 1E push ds
- 1.0427 681600 push 0016
- 1.042A 9AFFFF0000 call KERNEL.GETPROCADDRESS
- 1.042F 8946F4 mov [bp-0C], ax
- 1.0432 8956F6 mov [bp-0A], dx
- 1.0435 0BD0 or dx, ax
- 1.0437 7407 je 0440
- 1.0439 6A01 push 0001
- 1.043B 6A01 push 0001
- 1.043D FF5EF4 call far ptr [bp-0C]
-
- 1.0440 >68FFFF push selector 1:0000
- 1.0443 687B00 push 007B
- 1.0446 FF760C push word ptr [bp+0C]
- 1.0449 9AFFFF0000 call KERNEL.MAKEPROCINSTANCE
- 1.044E 8BF0 mov si, ax
- 1.0450 8956FA mov [bp-06], dx
- 1.0453 0BD0 or dx, ax
- 1.0455 7426 je 047D
- 1.0457 FF760C push word ptr [bp+0C]
- 1.045A 6A00 push 0000
- 1.045C 6A0A push 000A
- 1.045E 6A00 push 0000
- 1.0460 8B46FA mov ax, [bp-06]
- 1.0463 50 push ax
- 1.0464 56 push si
- 1.0465 8976EE mov [bp-12], si
- 1.0468 8946F0 mov [bp-10], ax
- 1.046B 9AFFFF0000 call USER.DIALOGBOX
- 1.0470 8BF8 mov di, ax
- 1.0472 FF76F0 push word ptr [bp-10]
- 1.0475 FF76EE push word ptr [bp-12]
- 1.0478 9AFFFF0000 call KERNEL.FREEPROCINSTANCE
-
- 1.047D >8B46F6 mov ax, [bp-0A]
- 1.0480 0B46F4 or ax, [bp-0C]
- 1.0483 7407 je 048C
- 1.0485 6A01 push 0001
- 1.0487 6A00 push 0000
- 1.0489 FF5EF4 call far ptr [bp-0C]
-
- 1.048C >8BC7 mov ax, di
-
- 1.048E >5E pop si
- 1.048F 5F pop di
- 1.0490 8BE5 mov sp, bp
- 1.0492 5D pop bp
- 1.0493 C20A00 ret 000A
-
- Let's begin from the last line: ret 000A. In the Pascal calling
- convention, the callee is responsible for clearing its arguments off
- the stack; this explains the RET A return. In this particular case,
- WinMain() is being invoked with a NEAR call. As we saw in the startup
- code, with the Pascal calling convention, arguments are pushed in
- "forward" order. Thus, from the prospective of the called function,
- the last argument always has the *lowest* positive offset from BP
- (BP+6 in a FAR call and BP+4 in a NEAR call, assuming the standard
- PUSH BP -> MOV BP,SP function prologue, like at the beginning of this
- WinMain().
-
- Now write the following in your cracking notes (the ones you really
- keep on your desk when you work... close to your cocktail glass):
- function parameters have *positive* offsets from BP, local variables
- have *negative* offsets from BP.
-
- What does all this mean... I hear some among you screaming... well, in
- the case of WinMain(), and in a small-model program like Taskman,
- which starts from BP+4, you'll have:
-
- int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance,
- LPSTR lpCmdLine, int nCmdShow);
- nCmdShow = word ptr [bp+4]
- lpCmdLine = dword ptr [bp+6]
- hPrevInstance = word ptr [bp+0Ah]
- hInstance = word ptr [bp+0Ch]
-
- Yeah... let's rewrite it:
-
- 1.03B6 2BFF sub di, di
- 1.03B8 397E0A cmp hPrevInstance, di
- 1.03BB 7405 je 03C2
- 1.03BD 2BC0 sub ax, ax
- 1.03BF E9CC00 jmp 048E
-
- 1.03C2 >C47606 les si, dword ptr lpCmdLine
- 1.03C5 26803C00 cmp byte ptr es:[si], 00
-
- We can now see, for example, that WinMain() checks if hPrevInstance is
- zero (sub di,di); if it isn't, it immediately jump to the pops and
- exits (jmp 048E).
-
- Look at the code of WinMain() once more... notice that our good
- Taskman appears to be inspecting its command line... funny: the
- Windows documentation says nothing about command line arguments to
- Taskman... Look around location 1.03D0 above, you'll see that Taskman
- appears to be looking for a space (20h), getting a character from the
- command line, multiplying it by 10 (0Ah), subtracting the character
- zero (30h) and doing other things that seem to indicate that it's
- looking for one or more *numbers*. The code line 1.03E7 SUB ax,30h
- it's a typical code line inside many routines checking for numbers.
- The hex ascii code for numbers is 30 for 0 to 39 for 9, therefore the
- transmutation of an ascii code in hex *number* is pretty easy: mov al,
- your_number and sub ax,30... you'll find it very often.
-
- Rather than delve further into the code, it next makes sense to *run*
- taskman, feeding it different numbers on the command line, and seeing
- what it does (it's surprising how few crackers think of actually going
- in and *running* a program before spending much time looking at its
- code).
-
- Normally Taskman runs when you type CTRL+ESC in Windows, but its just
- a regular program, that can be run with a command line, like any other
- program.
-
- Indeed, running "TASKMAN 1" behaves differently from just running
- "TASKMAN": it positions the Task List in the upper-left corner of the
- screen, instead of in the middle. "TASKMAN 666 666" (the number of the
- beast?) seems to position it in the lower right corner.
-
- Basically, the command line numeric arguments seem to represent an
- (x,y) position for our target, to override its default position in the
- middle of the screen.
-
- So you see, there are hidden 'goodies' and hidden 'secrets' even
- behind really trivial little programs like Taskman (and believe me:
- being able to identify this command line checking will be very useful
- ;-) when you'll crack applications and/or games that *always* have
- backdoors and hidden goodies).
-
- Back to the code (sip your favourite cocktail during your
- scrutinies... may I suggest a Traitor? -> see the legendary FraVia's
- cocktail page here) you can see that the variables [0010] and [0012]
- are being manipulated. What are these for?
-
- The answer is *not* to stare good and hard at this code until it makes
- sense, but to leave this area and see how the variables are used
- elsewhere in the program... maybe the code elsewhere will be easier to
- understand (for bigger applications you could in this case use a
- Winice breakpoint on memory range, but we'll remain with our WCB
- disassembly listing).
-
- In fact, if we search for data [0010] and [0012] we find them used as
- arguments to a Windows API function:
-
- 1.018B >A31200 mov [0012], ax
- 1.018E FF760E push word ptr [bp+0E]
- 1.0191 FF361000 push word ptr [0010]
- 1.0195 50 push ax
- 1.0196 56 push si
- 1.0197 57 push di
- 1.0198 6A00 push 0000
- 1.019A 9AFFFF0000 call USER.MOVEWINDOW
-
- This shows us *immediately* what [0010] and [0012] are. MoveWindows()
- is a documented function, whose prototype is:
-
- void FAR PASCAL MoveWindow(HWND hwnd, int nLeft, int nTop,
- int nWidth, int nHeight, BOOL fRepaint);
-
- 1.018B >A31200 mov [0012], ax
- 1.018E FF760E push word ptr [bp+0E] ;hwnd
- 1.0191 FF361000 push word ptr [0010] ;nLeft
- 1.0195 50 push ax ;nTop
- 1.0196 56 push si ;nWidth
- 1.0197 57 push di ;nHeight
- 1.0198 6A00 push 0000 ;fRepaint
- 1.019A 9AFFFF0000 call USER.MOVEWINDOW
-
- In other words, [0010] has to be nLeft and [0012] (whose contents have
- been set from AX) has to be nTop.
-
- Now you'll do another global "search and replace" on your WCB
- disassembly, changing every [0010] in the program (not just the one
- here) to nLeft, and every [0012] to nTop.
-
- A lot of Windows cracking is this easy: all Windows programs seem to
- do is call API functions, most of these functions are documented and
- you can use the documentation to label all arguments to the function.
- You then transfer these labels upward to other, possibly quite distant
- parts of the program.
-
- In the case of nLeft [0010] and nTop [0012], suddenly the code in
- WinMain() makes much more sense:
-
- 1.03C2 >C47606 les si, dword ptr lpCmdLine
- 1.03C5 26803C00 cmp byte ptr es:[si], 00 ; no cmd line?
- 1.03C9 7453 je 041E ; go elsewhere
- 1.03CB 897EF2 mov [bp-0E], di
- 1.03CE EB1E jmp 03EE
-
- 1.03D0 >26803C20 cmp byte ptr es:[si], 20 ; if space
- 1.03D4 741E je 03F4 ; go elsewhere
-
- 1.03D6 B80A00 mov ax, 000A
- 1.03D9 F72E1000 imul nLeft ; nleft *= 10
- 1.03DD A31000 mov nLeft, ax
- 1.03E0 8BDE mov bx, si
- 1.03E2 46 inc si
- 1.03E3 268A07 mov al, es:[bx]
- 1.03E6 98 cbw ; ax = char
- 1.03E7 2D3000 sub ax, 0030 ; ax='0' (char-> number)
- 1.03EA 01061000 add nLeft, ax ; nleft += number
-
- 1.03EE >26803C00 cmp byte ptr es:[si], 00 ; NotEndOfString
- 1.03F2 75DC jne 03D0 ; next char
- ...
-
- In essence, Taskman is performing the following operation here:
-
- static int nLeft, nTop;
- //...
- if (*lpCmdLine !=0)
- sscanf(lpCmdLine, "%u %u, &nLeft, &nTop);
-
- Should you want 3.1. Taskman to appear in the upper left of your
- screen, you could place the following line in the [boot] section of
- SYSTEM.INI:
-
- taskman.exe=taskman.exe 1 1
-
- In addition, doubleclicking anywhere on the Windows desktop will bring
- up Taskman with the (x,y) coordinates for the double click passed to
- Taskman on its command line.
-
- The USER!WM_SYSCOMMAND handler is responsible for invoking Taskman,
- via WinExec() whenever you press CTRL+ESC or double click the desktop.
-
- What else is going on in WinMain()? Let's look at the following block
- of code:
-
- 1.041E >6A29 push 0029
- 1.0420 9AF9000000 call USER.GETSYSTEMMETRICS
- 1.0425 50 push ax
- 1.0426 1E push ds
- 1.0427 681600 push 0016
- 1.042A 9AFFFF0000 call KERNEL.GETPROCADDRESS
- 1.042F 8946F4 mov [bp-0C], ax
- 1.0432 8956F6 mov [bp-0A], dx
- 1.0435 0BD0 or dx, ax
- 1.0437 7407 je 0440
- 1.0439 6A01 push 0001
- 1.043B 6A01 push 0001
- 1.043D FF5EF4 call far ptr [bp-0C] ; *1 entry
-
- The lines push 29h & CALL GETSYSTEMMETRICS are simply the assembly
- language form of GetSystemMetrics(0x29). 0x29 turns out to be
- SM_PENWINDOWS (look in WINDOWS.H for SM_).
-
- Thus, we now have GetSystemMetrics(SM_PENWINDOWS). If we read the
- documentation, it says that this returns a handle to the Pen Windows
- DLL if Pen Windows is installed. Remember that 16-bit return values
- *always* appear in the AX register.
-
- Next we can see that AX, which must be either 0 or a Pen Window module
- handle, is pushed on the stack, along with ds:16h.
-
- Let's immediately look at the data segment, offset 16h:
-
- 2.0010 0000000000005265 db 00,00,00,00,00,00,52,65 ; ......Re
- 2.0018 6769737465725065 db 67,69,73,74,65,72,50,65 ; gisterPe
- 2.0020 6E41707000000000 db 6E,41,70,70,00,00,00,00 ; nApp....
-
- Therefore:
-
- 2.0016 db 'RegisterPenApp',0
-
- Thus, here is what we have so far:
-
- GetProcAddress(
- GetSystemMetrics(SM_PENWINDOWS),
- "RegisterPenApp")
-
- GetProcAddress() returns a 4 bytes far function pointer (or NULL) in
- DX:AX. In the code from WinMain() we can see this being moved into the
- DWORD at [bp+0Ch] (this is 16-bit code, so moving a 32-bit value
- requires two operations).
-
- It would be nice to know what the DWORD at [bp-0Ch] is. But, hey! We
- *do* know it already: it's a copy of the return value from
- GetProcAddress(GetSystemMetrics(SM_PENWINDOWS), "RegisterPenApp)! In
- other words, is a far pointer to the RegisterPenApp() function, or
- NULL if Pen Windows is not installed. We can now replace all
- references to [bp-0Ch] with references to something like
- fpRegisterPenApp.
-
- Remember another advantage of this "dead" Windows disassembling
- vis-a-vis of the Winice approach "on live": here you can choose,
- picking *meaningful* references for your search and replace
- operations, like "mingling_bastard_value" or "hidden_and_-
- forbidden_door". The final disassembled code may become a work of art
- and inspiration if the cracker is good! (My disassemblies are
- beautiful works of poetry and irony). Besides, *written*
- investigations will remain documented for your next cracking session,
- whereby with winice, if you do not write everything down immediately,
- you loose lots of your past work (it's incredible how much place and
- importance retains paper in our informatic lives).
-
- After our search and replaces, this is what we get for this last block
- of code:
-
- FARPROC fpRegisterPenAPP;
- fpRegisterPenApp = GetProcAddress(
- GetSystemMetrics(SM_PENWINDOWS),
- "RegisterPenApp");
-
- Next we see [or dx, ax] being used to test the GetProcAddress() return
- value for NULL. If non-NULL, the code twice pushes 1 on the stack
- (note the PUSH IMMEDIATE here... Windows applications only run on
- 80386 or higher processors... there is no need to place the value in a
- register first and then push that register) and then calls through the
- fpRegisterPenApp function pointer: 1.0435 0BD0 or dx, ax 1.0437 7407
- je 0440 1.0439 6A01 push 0001 1.043B 6A01 push 0001 1.043D FF5EF4 call
- dword ptr fpRegisterPenApp
-
- 1.0435 0BD0 or dx, ax
- 1.0437 7407 je 0440
- 1.0439 6A01 push 0001
- 1.043B 6A01 push 0001
- 1.043D FF5EF4 call dword ptr fpRegisterPenApp
-
- Let's have a look at the Pen Windows SDK doucmentation (and PENWIN.H):
-
- #define RPA_DEFAULT
- void FAR PASCAL RegisterPenApp(UINT wFlags, BOOL fRegister);
-
- We can continue in this way with all of WinMain(). When we are done,
- the 100 lines of assembly language for WinMain() boild own to the
- following 35 lines of C code:
-
- // nLeft, nTop used in calls to MoveWindow() in TaskManDlgProc()
- static WORD nLeft=0, nTop=0;
- BOOL FAR PASCAL TaskManDlgProc(HWND hWndDlg, UINT msg, WPARAM
- wParam, LPARAM lParam);
- int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance,
- LPSTR lpCmdLine, int nCmdShow)
- {
- void (FAR PASCAL *RegisterPenApp) (UINT,BOOL);
- FARPROC fpDlgProc;
- if (hPrevhInstance != 0)
- return 0;
- if (*lpCmdLine !=0 )
- _fsscanf(lpCmdLine, "%u %u, &nLeft, &nTop); // pseudocode
- RegisterPenApp = GetProcAddress(GetSystemMetrics(SM_PENWINDOWS),
- "RegisterPenApp");
- if (RegisterPenApp != 0)
- (*RegisterPenApp) (RPA_DEFAULT, TRUE);
- if (fpDlgProc = MakeProchInstance(TaskManDlgProc, hInstance))
- {
- DialogBox(hInstance, MAKEINTRESOURCE(10), 0, fpDlgProc);
- FreeProcHInstance(fpDlgProc);
- }
- if (RegisterPenApp != 0)
- (*RegisterPenApp) (RPA_DEFAULT, FALSE);
- return 0;
- }
-
- In this lesson we had a look at WinMain()... pretty interesting, isn't
- it? We are not done with TASKMAN yet, though... we'll see in the next
- lesson wich windows and dialog procedures TASKMAN calls. (-> lesson 2)
-
- FraVia
-